/*
 * TaskThread.cpp
 *
 *  Created on: 2020年8月22日
 *      Author: chuanjiang.zh
 */

#include "TaskThread.h"
#include "CPollTimerQueue.h"
#include "CLog.h"
#include "ClockTime.h"


namespace comn
{

TaskThread::TaskThread()
	: m_timerQueue(new CPollTimerQueue())
	, m_timerDegree(TIMER_DEGREE)
{
}

TaskThread::~TaskThread()
{
	if (isRunning())
	{
		stop();
	}

	m_timerQueue->clear();
	delete m_timerQueue;
}

void TaskThread::post(Task task)
{
	{
		std::lock_guard< std::mutex >	lock(m_taskMutex);
		m_taskQueue.push_back(task);
	}

	postEvent();
}

void TaskThread::clearTask()
{
	{
		std::lock_guard< std::mutex >	lock(m_taskMutex);
		m_taskQueue.clear();
	}

	postEvent();
}

void TaskThread::onIdle()
{
	int ms = m_timerQueue->poll();
	if (ms < 0)
	{
		ms = IDLE_DURATION;
	}
	else if (ms > IDLE_DURATION)
	{
		ms = IDLE_DURATION;
	}

	timedwait(ms);
}

int TaskThread::run()
{
	int64_t startTime = getTime();

	while (!m_canExit)
	{
		int64_t curTime = 0;
		if (fetchAndHandle(curTime))
		{
			int64_t elapse = (curTime - startTime);
			if (elapse >= m_timerDegree)
			{
				poll();

				startTime = getTime();
			}
		}
		else
		{
			onIdle();

			startTime = getTime();
		}
	}
	return 0;
}

void TaskThread::doStop()
{
	postEvent();
}

bool TaskThread::fetchAndHandle()
{
	int64_t curTime = 0;
	return fetchAndHandle(curTime);
}

bool TaskThread::fetchAndHandle(int64_t& curTime)
{
	Task task;
	if (!fetchTask(task))
	{
		return false;
	}
	
	int64_t startTime = getTime();
	
	task();
	
	curTime = getTime();
	int elapse = (int)(curTime - startTime);

	if (elapse > OVERRUN_TIME)
	{
		CLog::warning("TaskThread::fetchAndHandle. overrun. elapse: %d ms\n", elapse);
	}

	return true;
}

bool TaskThread::fetchTask(Task& task)
{
	bool got = false;
	std::lock_guard< std::mutex >	lock(m_taskMutex);
	if (m_taskQueue.size() > 0)
	{
		task = m_taskQueue.front();
		m_taskQueue.pop_front();
		got = true;
	}
	return got;
}

int TaskThread::addTimer(uint32_t ms, TimerTask task)
{
	int tid = m_timerQueue->addTimer(ms, task);

	postEvent();
	return tid;
}

int TaskThread::addElapse(uint32_t ms, TimerTask task)
{
	int tid = m_timerQueue->addElapse(ms, task);

	postEvent();
	return tid;
}

void TaskThread::cancelTimer(int tid)
{
	m_timerQueue->cancel(tid);

	postEvent();
}

void TaskThread::clearTimer()
{
	m_timerQueue->clear();

	postEvent();
}

int TaskThread::poll()
{
	return m_timerQueue->poll();
}

int64_t TaskThread::getTime()
{
	return comn::ClockTime::getTime();
}

bool TaskThread::timedwait(int ms)
{
	return m_eventTask.timedwait(ms);
}

void TaskThread::postEvent()
{
	m_eventTask.post();
}

size_t TaskThread::getQueueSize()
{
	std::lock_guard< std::mutex >	lock(m_taskMutex);
	return m_taskQueue.size();
}


}